package com.jxc.wiki.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jxc.wiki.entity.User;
import com.jxc.wiki.entity.UserExample;
import com.jxc.wiki.custException.BusinessException;
import com.jxc.wiki.custException.BusinessExceptionCode;
import com.jxc.wiki.mapper.UserMapper;
import com.jxc.wiki.request.UserLoginParamReq;
import com.jxc.wiki.request.UserQueryParamReq;
import com.jxc.wiki.request.UserResetPasswordParamReq;
import com.jxc.wiki.request.UserSaveParamReq;
import com.jxc.wiki.response.PageParamResp;
import com.jxc.wiki.response.UserLoginParamResp;
import com.jxc.wiki.response.UserQueryParamResp;
import com.jxc.wiki.service.UserService;
import com.jxc.wiki.util.CopyClassOrListUtil;
import com.jxc.wiki.util.SnowFlakeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    private static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserMapper mapper;

    @Resource
    private SnowFlakeUtil snowFlakeUtil;

    public PageParamResp<UserQueryParamResp> list(UserQueryParamReq req){


        // 实现输入名字查询电子书的功能，用到了模糊查询
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        // 通过判断请求的name参数是否为空（通过输入名字查询某本电子书）,不为空则使用模糊查询，没有参数的话返回所有电子书列表
        if (!ObjectUtils.isEmpty(req.getLoginName())){
            criteria.andLoginNameEqualTo(req.getLoginName());
        }
        // 通过判断请求的categoryId2参数是否为空（通过输入二级分类id查询某本电子书）,不为空则使用模糊查询，没有参数的话返回所有电子书列表
//        if (!ObjectUtils.isEmpty(req.getCategoryId2())){
//            criteria.andCategory2IdEqualTo(req.getCategoryId2());
//        }
        PageHelper.startPage(req.getPage(),req.getSize());
        List<User> userList = mapper.selectByExample(userExample);
        // 打印分页情况日志
        PageInfo<User> pageInfo = new PageInfo<>(userList);
        LOG.info("总行数：{}", pageInfo.getTotal());
        LOG.info("总页数：{}", pageInfo.getPages());
//        // 把类型为User的集合的值拷贝到类型为UserResp的集合里
//        List<UserResp> userRespList = new ArrayList<>();
//        for (User user : userList) {
//            UserResp userResp = new UserResp();
//            // BeanUtils工具类，可以把user的值快速拷贝给userResp
//            BeanUtils.copyProperties(user,userResp);
//            userRespList.add(userResp);
//        }

        // 自定义Copy工具类(运用了反射的知识)快速拷贝
        List<UserQueryParamResp> userRespList = CopyClassOrListUtil.copyList(userList, UserQueryParamResp.class);

        PageParamResp<UserQueryParamResp> pageParamResp = new PageParamResp<>();
        pageParamResp.setTotal(pageInfo.getTotal());
        pageParamResp.setList(userRespList);
        return pageParamResp;
    }

    // 保存功能,通过插入一条新的数据或者更新一条新的数据实现
    public void save(UserSaveParamReq req){
        User user = CopyClassOrListUtil.copy(req,User.class);
        if (ObjectUtils.isEmpty(req.getId())){
            if (ObjectUtils.isEmpty(selectByLoginName(req.getLoginName()))){
                // 如果id的值为空，则为新增数据,用雪花算法生成id，并设置为user的id
                user.setId(snowFlakeUtil.nextId());
                mapper.insert(user);
            }else {
                // 用户名已存在
                throw new BusinessException(BusinessExceptionCode.USER_LOGIN_NAME_EXIST);
            }

        }else {
            // 防黑客修改数据，先设置LoginName和密码为空
            user.setLoginName(null);
            user.setPassword(null);
            // updateByPrimaryKeySelective的效果是如果参数user里面有值，才去更新数据（编辑的时候，原先一定有除了loginName以外的值），
            // 没有值就不更新
            mapper.updateByPrimaryKeySelective(user);
        }
    }

    public void delete(Long id){
        mapper.deleteByPrimaryKey(id);
    }

    public User selectByLoginName(String loginName){
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andLoginNameEqualTo(loginName);
        List<User> userList = mapper.selectByExample(userExample);
        if (CollectionUtils.isEmpty(userList)){
            // 如果列表为空，则返回null
            return null;
        }else {
            // 如果列表不为空，则返回一条也是唯一的一条数据
            return userList.get(0);
        }
    }


    // 修改密码
    public void resetPassword(UserResetPasswordParamReq req){
        req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));
        User user = new User();
        BeanUtils.copyProperties(req, user);
        // 创建查询条件，条件为根据id来匹配数据
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andIdEqualTo(user.getId());
        // 根据上面设置好的条件来查询，传入查询条件以及user（主要是判断user里面是否为空，要不要更新密码）
        mapper.updateByExampleSelective(user, userExample);
    }

    // 登录
    public UserLoginParamResp login(UserLoginParamReq req){
        req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));
        // 根据用户名查是否有这个用户（不用用户名+密码）,查出整条数据
        User user = selectByLoginName(req.getLoginName());
        if (ObjectUtils.isEmpty(user)){
            // 写给后端看的日志,频繁出现这个日志说明可能有人在攻击
            LOG.info("用户名不存在，{}",req.getLoginName());
            // 如果为空则说明用户名不存在,抛出自定义异常中断业务
            throw new BusinessException(BusinessExceptionCode.LOGIN_USER_ERROR);
        }else {
            // 进到这里说明用户名存在，如果密码对得上的话则登陆成功
            if (user.getPassword().equals(req.getPassword())){
                // 登陆成功
                UserLoginParamResp resp = CopyClassOrListUtil.copy(user, UserLoginParamResp.class);
                return resp;
            }else {
                // 写给后端看的日志,频繁出现这个日志说明可能有人在攻击，可以设置五次密码输入上限
                LOG.info("密码不正确，用户输入的密码：{},数据库中存的密码：{}",req.getPassword(),user.getPassword());
                // 密码不正确，登录失败,抛出自定义异常中断业务
                throw new BusinessException(BusinessExceptionCode.LOGIN_USER_ERROR);
            }
        }
    }

    public void logout(String token){
        stringRedisTemplate.delete(token);
        LOG.info("从redis中清除了token：{}",token);
    }
}
